/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frprotocol_default.h                               */
/*  NOTE      = 默认协议                                           */
/*  DATE      = 2015/01/04 yaohl                                   */
/*******************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frconfig.h"

#include "frame_params.h"
#include "frproto_l7default.h"

static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

/* 按tcp/udp组织的默认协议 */
#define FRPROTO_DEFAULT_TCP     0
#define FRPROTO_DEFAULT_UDP     1
#define FRPROTO_DEFAULT_ANY     2
static Frmodule_mng *g_p_st_proto_default[3]={NULL, NULL, NULL};

/*******************************************************************************
*  FUNC     :  默认协议管理资源初始化
*  ARGS     :
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
//int frproto_l7default_init(void)
//{
//    return FR_SUCC;
//}

/*******************************************************************************
*  FUNC     :  模默认协议管理资源释放
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
//void frproto_l7default_destory(void)
//{
//    return;
//}

/*******************************************************************************
*  FUNC     :  设置l7默认解析协议
*  ARGS     :  ip_proto         (tcp: IPPROTO_TCP; udp: IPPROTO_UDP; any: IPPROTO_TCP|IPPROTO_UDP )
*           :  i_l7_proto      (全局使用的l7代号 )
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frproto_l7default_add(u_short ip_proto, int i_l7_proto)
{
    Frmodule_mng *p_st_module_mng=NULL;

    if(ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP && ip_proto != (IPPROTO_TCP|IPPROTO_UDP) )
        return FR_FAIL;

    p_st_module_mng = frmodule_get_module(i_l7_proto);
    if(p_st_module_mng == NULL)
    {
        FRLOG_WARN_DETAIL("module is not exist(IPPROTO=%s;l7=%d)", FR_L4PROTO2STR(ip_proto), i_l7_proto);
        return FR_FAIL;
    }

    pthread_rwlock_rdlock(&rwlock);
    switch(ip_proto)
    {
        case IPPROTO_TCP:
            g_p_st_proto_default[FRPROTO_DEFAULT_TCP] = p_st_module_mng;
            break;
        case IPPROTO_UDP:
            g_p_st_proto_default[FRPROTO_DEFAULT_UDP] = p_st_module_mng;
            break;
        default:
            g_p_st_proto_default[FRPROTO_DEFAULT_ANY] = p_st_module_mng;
            break;
    }
    pthread_rwlock_unlock(&rwlock);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  取消l7默认解析协议
*  ARGS     :  ip_proto         (tcp: IPPROTO_TCP; udp: IPPROTO_UDP; any: IPPROTO_TCP|IPPROTO_UDP )
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frproto_l7default_del(u_short ip_proto)
{
    if(ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP && ip_proto != (IPPROTO_TCP|IPPROTO_UDP) )
        return FR_FAIL;

    pthread_rwlock_rdlock(&rwlock);
    switch(ip_proto)
    {
        case IPPROTO_TCP:
            g_p_st_proto_default[FRPROTO_DEFAULT_TCP] = NULL;
            break;
        case IPPROTO_UDP:
            g_p_st_proto_default[FRPROTO_DEFAULT_UDP] = NULL;
            break;
        default:
            g_p_st_proto_default[FRPROTO_DEFAULT_ANY] = NULL;
            break;
    }
    pthread_rwlock_unlock(&rwlock);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  获取l7默认解析协议
*  ARGS     :  ip_proto         (tcp: IPPROTO_TCP; udp: IPPROTO_UDP; any: IPPROTO_TCP|IPPROTO_UDP )
*  RTN      :  成功:Frmodule_mng *;失败:NULL
*  NOTE     :
*******************************************************************************/
Frmodule_mng *frproto_l7default_find(u_short ip_proto)
{
    Frmodule_mng *p_st_module_mng=NULL;

    if(ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP && ip_proto != (IPPROTO_TCP|IPPROTO_UDP) )
        return NULL;

    pthread_rwlock_rdlock(&rwlock);
    switch(ip_proto)
    {
        case IPPROTO_TCP:
            p_st_module_mng = g_p_st_proto_default[FRPROTO_DEFAULT_TCP];
            break;
        case IPPROTO_UDP:
            p_st_module_mng = g_p_st_proto_default[FRPROTO_DEFAULT_UDP];
            break;
        default:
            p_st_module_mng = g_p_st_proto_default[FRPROTO_DEFAULT_ANY];
    }
    pthread_rwlock_unlock(&rwlock);

    return p_st_module_mng;
}

/*******************************************************************************
*  FUNC     :  l7默认解析协议内容出力
*  ARGS     :
*  RTN      :
*  NOTE     :  pp_result需要在外部释放内存
*******************************************************************************/
void frproto_l7default_output(char **pp_result)
{
    char *p_outbuff=NULL, arr_buff[56];
    int i_outbuff_size =1024, i_idx=0;

    p_outbuff = frmalloc(i_outbuff_size);
    if(p_outbuff==NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        return;
    }

    snprintf(p_outbuff, i_outbuff_size, "l7 default\n\t#ip_proto:l7_proto\n");
    i_outbuff_size -= strlen(p_outbuff);

    for(i_idx=0; i_idx < 3; i_idx++)
    {
        if(g_p_st_proto_default[i_idx] == NULL)
            continue;

        snprintf(arr_buff, sizeof(arr_buff), "\t%s:%d\n"
                , i_idx==0?"tcp":(i_idx==1?"udp":"any")
                , g_p_st_proto_default[i_idx]->st_l7_module.i_l7_proto);
        strcat(p_outbuff, arr_buff);
    }

    if(pp_result == NULL)
    {
        frdbg("==========================\n");
        printf("output l7default data\n%s\n", p_outbuff);
        frdbg("==========================\n");
        frfree(p_outbuff);
    }
    else
        *pp_result = p_outbuff;

    return;
}

/*******************************************************************************
*  FUNC     :  获取 ip_proto,l7协议号
*  ARGS     :  p_token_lib      (解析用字符串)
*           :  p_ip_proto       (tcp: IPPROTO_TCP; udp: IPPROTO_UDP; any: IPPROTO_TCP|IPPROTO_UDP )
*           :  p_i_l7_proto     (全局使用的l7代号 )
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  函数内部没有分配内存,没有内存释放的问题
*******************************************************************************/
static int __frproto_cfg_get_param(char *p_token_data
                                     , u_short *p_ip_proto
                                     , int *p_i_l7_proto)
{
    char *p_temp=NULL;

    if(p_token_data == NULL || *p_token_data == '\0'
       || p_ip_proto == NULL || p_i_l7_proto==NULL)
        return FR_FAIL;

    //ip_proto
    p_temp = strsep(&p_token_data,":");
    if(p_temp == NULL || *p_temp == '\0')
        return FR_FAIL;
    if(strcasecmp("tcp", p_temp) == 0)
        *p_ip_proto = IPPROTO_TCP;
    else if(strcasecmp("udp", p_temp) == 0)
        *p_ip_proto = IPPROTO_UDP;
    else if(strcasecmp("any", p_temp) == 0)
        *p_ip_proto = IPPROTO_TCP | IPPROTO_UDP;
    else
        return FR_FAIL;

    //l7协议号
    p_temp = p_token_data;
    if(p_temp == NULL || *p_temp == '\0')
        return FR_FAIL;
    *p_i_l7_proto = atoi(p_temp);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  从配置文件中读取l7默认解析协议
*  ARGS     :  i_reload          (FR_YES:重新加载; FR_NO:不重新加载,一般程序启动时使用FR_NO)
*  RTN      :  FR_SUCC / FR_FAIL
*  NOTE     :
*******************************************************************************/
int frproto_l7default_load(int i_reload)
{
    char *p_l7default=NULL, *p_token_l7default=NULL;
    u_short us_proto;
    int   i_l7_proto;
    char arr_one_l7default[256];
    int i_ret_fun = FR_FAIL;

    i_ret_fun = frconfig_get_string(APM_CFG_FILENAME_ANALYZER, APM_ANALYZER_KEY_L7_DEFAULT, &p_l7default);
    if(i_ret_fun != APM_FRCONFIG_SUCC || p_l7default == NULL)
    {
        FRLOG_ERROR_DETAIL("open cfg[%s][%s] err", APM_CFG_FILENAME_ANALYZER, APM_ANALYZER_KEY_L7_DEFAULT);
        return FR_FAIL;
    }

    if(i_reload == FR_YES)
    {
        pthread_rwlock_rdlock(&rwlock);
        g_p_st_proto_default[FRPROTO_DEFAULT_TCP] = NULL;
        g_p_st_proto_default[FRPROTO_DEFAULT_UDP] = NULL;
        g_p_st_proto_default[FRPROTO_DEFAULT_ANY] = NULL;
        pthread_rwlock_unlock(&rwlock);
    }

    p_token_l7default = strtok(p_l7default,";");
    while(p_token_l7default != NULL)
    {
        //获取ip_proto, l7_proto
        snprintf(arr_one_l7default, sizeof(arr_one_l7default), "%s", p_token_l7default);
        i_ret_fun = __frproto_cfg_get_param(arr_one_l7default, &us_proto, &i_l7_proto);
        if(i_ret_fun== FR_FAIL)
        {
            FRLOG_WARN_DETAIL("config [%s] err", arr_one_l7default);
            //取下一个协议解析库
            p_token_l7default = strtok(NULL,";");
            continue;
        }
        //frdbg("%s [%s(%d)]:[%d]\n", arr_one_l7default, FR_L4PROTO2STR(us_proto), us_proto, i_l7_proto);
        frproto_l7default_add(us_proto, i_l7_proto);

        p_token_l7default = strtok(NULL,";");
    }

    if(p_l7default)
        frfree(p_l7default);

    //frproto_l7default_output(NULL);

    return FR_SUCC;
}


